package com.study.gateway.service;

import com.study.gateway.entry.GateWayEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 网关服务，动态配置网关转发配置。
 * @author: BacHe
 * @email: 1218585258@qq.com
 * @Date: 2020/9/24 0:45
 */
@Service // 用动态配置时，不要与配置文件冲突。
public class GatewayService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    @Autowired  //网关内置的类
    private RouteDefinitionWriter routeDefinitionWriter;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
    //写死的刷新网关。
    public String loadRoute(){
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        Map<String, String> filterParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();

        //如果配置路由type为 0 的话，则从注册中心获取服务

        URI uri = UriComponentsBuilder.fromUriString("lb://order/").build().toUri();
        //定义的路由唯一ID
        definition.setId("order");
        predicate.setName("Path");
        //路由转发地址
        predicateParams.put("pattern", "/order/**");
        predicate.setArgs(predicateParams);
        //名称是固定的，路径去前缀
        filterDefinition.setName("StripPrefix");
        filterParams.put("_genkey_0", "1");

        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));
        definition.setUri(uri);
        //订阅subscribe
        routeDefinitionWriter.save(Mono.just(definition))
                .subscribe();
        //发布事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

    //读数据库，获取配置实体类，再动态刷新网关。
    public String loadRoute(GateWayEntry gateWayEntry) {
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        Map<String, String> filterParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();

        URI uri = null;
        if ("0".equals(gateWayEntry.getRouteType())) {
            //如果配置路由type为 0 的话，则从注册中心,动态获取服务地址,经过了负载均衡
            //   lb://order/
            uri = UriComponentsBuilder.fromUriString("lb://" + gateWayEntry.getRouteUrl() + "/").build().toUri();
        } else {
            //写死的url地址  http://127.0.0.1:8091
            uri = UriComponentsBuilder.fromHttpUrl(gateWayEntry.getRouteUrl()).build().toUri();
        }
        //定义的路由唯一ID
        definition.setId(gateWayEntry.getRouteId());
        //路由转发地址
        predicateParams.put("pattern", gateWayEntry.getRoutePattern());

        predicate.setName("Path");
        predicate.setArgs(predicateParams);
        //名称是固定的，路径去前缀
        filterDefinition.setName("StripPrefix");
        filterParams.put("_genkey_0", "1");

        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));
        definition.setUri(uri);
        //订阅subscribe
        routeDefinitionWriter.save(Mono.just(definition))
                .subscribe();
        //发布事件
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }

}
